import backtrader as bt
import numpy as np
import pandas as pd
import traceback

from indicators.KeyPointsInd import KeyPointsInd
from indicators.bias_ind import bias_ind
from indicators.wave_index_ind import wave_index_ind


class nowKeyPointsStrategy(bt.Strategy):
    # 策略参数
    params = dict(
        period=20,  # 均线周期
        look_back_days=30,
        printlog=False,
        period_ema_fast=10,
        period_ema_slow=100,
        short_window=20,
        long_window=60,
        N1=3,
        N2=50,
        N3=25,
        key_window=25,
        wave_two_window=50,
        wave_three_window=70,
        wave_window=20,
        distance=20,
        prominence=1
    )
    def __init__(self):
        try:
         for data in self.datas:
           data.bias24 = bias_ind(wave_window=self.p.wave_window, data=data.close)
           data.stockdata = KeyPointsInd().getwave(distance=self.p.distance,prominence=self.p.prominence, data=data,show=False,ago=None,size=None)
           data.resistance_val=0
           data.resistance_val_list=[]
           data.resistance_buy = 0  # 突破买入点
           data.resistance_sell = 0  # 跌破卖出点
           data.profit_sell = 0#盈利卖出
           data.resistance_val = 0# 阻力点
           data.resistance_len =0 # 阻力点发生的位置
           data.resistance_h_and_l=0#高点地点相加作为标识符使用
           data.short_ma = bt.indicators.SMA(data.close, period=self.p.short_window)
           data.profit = 0
           data.resistance_h=0#阻力
           data.resistance_h_ind=0
           data.resistance_bili = 0#最小比例值

           data.resistance_sell_order=0 #已生成订单的止损点
           data.profit_sell_order = 0  # 已生成订单的盈利卖出

           #data.bias24 = bias_ind(wave_window=25, data=data.close)

           data.profit_h_order = 0  # 订单中的高点
           data.order_price=0#订单买入价
           #for A, B in zip(stockdata['val'], stockdata['ind']):
           #    print(A, B)
           #    print(KeyPointsInd)
        except Exception as e:
            traceback.print_exc()

        #遍历所有股票,计算20日均线
        #for data in self.datas:

    def notify_order(self, order):
        """
        订单状态处理
        Arguments:
            order {object} -- 订单状态
        """
        if order.status in [order.Submitted, order.Accepted]:
            # 如订单已被处理，则不用做任何事情
            return

        # 检查订单是否完成
        if order.status in [order.Completed]:
            if order.isbuy():
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
                #print('BUY成交, 执行价={0}, {1}'.format(order.executed.price, order.executed.size))
                #elif order.issell():
                #print('SELL成交, 执行价={0}, {1}'.format(order.executed.price, order.executed.size))
            self.bar_executed = len(self)
        # 订单因为缺少资金之类的原因被拒绝执行
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')
        # 订单状态处理完成，设为空
        self.order = None

    def notify_trade(self, trade):
        """
        交易成果

        Arguments:
            trade {object} -- 交易状态
        """
        if not trade.isclosed:
            return

        # 显示交易的毛利率和净利润
        self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                 (trade.pnl, trade.pnlcomm), doprint=True)

    def next(self):
      try:
        total_value = self.broker.getvalue()
        p_value = total_value * 0.9/10
        for data in self.datas:

          if len(data) == (data.buflen()):

            pos = self.getposition(data).size
            stockdata = data.stockdata

            #print(stockdata.index)

            if self.getFrontMinB(data, 5,data.low[0]) == False:
                return
            #print(len(data))
            h = self.getKeyNum(stockdata, len(data), 1) # 前高点
            if h is not None and not pos:
               l = self.getKeyNum(stockdata, h.ind, 2)  # 前高点
               if l is not None:
                 resistance = (h.val - l.val) / l.val
                 bili = int(resistance+1)*2
                 if bili == 0 :
                     continue
                 #最小分数
                 bili=(resistance/bili)/2
                 if bili <0.1:
                     continue
                 #resistance_val=h.val -(h.val * bili)

                 for i in range(2, 4):
                     resistance_val = h.val - (h.val * bili*i)#关键线
                     #判断阻力线是否已被触及，当前及之前
                     if data.resistance_val==resistance_val  or resistance_val  in data.resistance_val_list \
                             or ((h.val +l.val)==data.resistance_h_and_l and data.resistance_val<resistance_val):
                         continue
                     if data.high[0] > resistance_val and data.low[0] < resistance_val:
                         data.resistance_buy=(resistance_val*bili*0.75)+resistance_val
                         data.resistance_h =data.high[0]
                         data.resistance_h_ind = h.ind
                         data.resistance_bili=bili
                             #data.high[0]#突破买入点
                         data.resistance_sell =resistance_val- (resistance_val*bili)
                             #resistance_val- (resistance_val*bili)
                             #data.low[0]  # 跌破卖出点
                         data.profit_sell=(resistance_val*bili*2)+resistance_val
                         data.resistance_val = resistance_val#写入回测数据众
                         data.resistance_len = len(data)#阻力点发生的位置

                         if self.getFrontMinB(data, 3,data.resistance_val) == False:
                             return
                         #加入背离判断
                         if data.bias24[0]-data.bias24[-1] > 1 :
                           print(data.datetime.date(0),'代码:',data._name,'买入位:',data.resistance_buy,'阻力位:',data.resistance_val,'高点:',h.val,'低点:',l.val)
                           data.resistance_h_and_l = h.val +l.val # 阻力数据相加，作为标识符

      except Exception as e:
        print ( "Finished with error: ", e )
    def log(self, txt, dt=None,doprint=False):
        if self.params.printlog or doprint:
            dt = dt or self.datas[0].datetime.date(0)
            print ( f'{dt.isoformat()},{txt}' )
    #  or self.getFrontB( data, 3) == True
    def getFrontB(self, data,  end):
        for i in range(1, end):
            if data.close[-i] > data.close[-(i+1)]:
                return False
        return True
    def getFrontMinB(self, data,  end,resistanceDat):
        for i in range(0, end):
            if resistanceDat > data.low[-(i+1)]:
                return False
        return True
    def getFrontMinResistance(self, data,  end):
        for i in range(0, end):
            if data.low[0] > data.low[-(i+1)]:
                return False
        return True
    #冒泡查询
    def getKeyNum(self, stockdata, indNum,dataType):
        data=None
        for row in stockdata.itertuples():
            ind = row.ind
            type =row.type
            if type == dataType and indNum > ind :
                data = row
                break
        return data
    #
    def getResistance_sell_order(self, data):
        bili = data.resistance_bili
        close= data.close[0]
        low= data.low[0]
        resistance_val=data.resistance_val
        for i in range(1, 20):
            d = resistance_val+(resistance_val*bili*i)
            if low > d:
                data.resistance_sell_order = d*0.8  # 已生成订单的止损点

    #记录交易收益情况（可省略，默认不输出结果）
    #def notify_trade(self,trade):
    #    if not trade.isclosed:
    #        return
    #    self.log(f'策略收益：\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}')
